---
title: "测试中的Mock & Spy"
date: 2019-10-9
categories:
- java
tags:
---

<div id="content">
<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org17f6f6a">JUnit</a></li>
<li><a href="#org5c3a22d">Mock</a></li>
<li><a href="#org166242d">Spy</a>
<ul>
<li><a href="#orgd690085">when… thenReturn…</a></li>
<li><a href="#orgffdf463">doReturn…when…</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="outline-2" id="outline-container-org17f6f6a">
<h2 id="org17f6f6a">JUnit</h2>
<div class="outline-text-2" id="text-org17f6f6a">
<blockquote>
<p>
<a href="https://stackoverflow.com/questions/14010222/junit-new-instance-before-invoking-each-test-method-what-are-the-benefits">https://stackoverflow.com/questions/14010222/junit-new-instance-before-invoking-each-test-method-what-are-the-benefits</a>
</p>
</blockquote>
<p>
JUnit creates a new instance of the test class before invoking each @Test method. This helps provide independence between test methods and avoids unintentional side effects in the test code. Because each test method runs on a new test class instance, we can’t reuse instance variable values across test methods.
</p>
</div>
</div>
<div class="outline-2" id="outline-container-org5c3a22d">
<h2 id="org5c3a22d">Mock</h2>
<div class="outline-text-2" id="text-org5c3a22d">
<p>
指定需要mock的类型类（接口或者实现类），生成 Mock 类，其中所有的方法都不是真实的方法，而且返回值都是NULL。
</p>
<div class="org-src-container">
<pre class="src src-java"><span style="font-weight: bold;">public</span> <span style="font-weight: bold;">class</span> <span style="font-weight: bold; text-decoration: underline;">Service</span> {
    <span style="font-weight: bold;">public</span> <span style="font-weight: bold; text-decoration: underline;">String</span> <span style="font-weight: bold;">service</span>() {
        System.out.print(<span style="font-style: italic;">"invoked!"</span>);
        <span style="font-weight: bold;">return</span> <span style="font-style: italic;">"real service!"</span>;
    }
}
<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">快速生成一个 Mock 类</span>
<span style="font-weight: bold; text-decoration: underline;">Service</span> <span style="font-weight: bold; font-style: italic;">mock</span> = Mockito.mock(Service.<span style="font-weight: bold;">class</span>);
System.out.println(mock.service());
<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">终端输出：null </span>
<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">打桩( stubbed )</span>
when(mock.service()).thenReturn(<span style="font-style: italic;">"mock"</span>);
<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">再次调用mock.service()，终端将输出：mock</span>
</pre>
</div>
</div>
</div>
<div class="outline-2" id="outline-container-org166242d">
<h2 id="org166242d">Spy</h2>
<div class="outline-text-2" id="text-org166242d">
<p>
监视一个真实的对象，这时对它进行方法调用将执行真实的方法，同时也可以打桩指定的方法。
</p>
<div class="org-src-container">
<pre class="src src-java"><span style="font-weight: bold; text-decoration: underline;">Service</span> <span style="font-weight: bold; font-style: italic;">spy</span> = Mockito.spy(<span style="font-weight: bold;">new</span> <span style="font-weight: bold; text-decoration: underline;">Service</span>());
<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">调用spy.service()方法，终端将输出：invoked! real service!</span>
<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">打桩( Stubbed )</span>
doReturn(<span style="font-style: italic;">"spy!"</span>).when(spy).service();
<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">调用spy.service()方法，终端输出：spy!</span>
</pre>
</div>
<p>
SPY打桩的两种方法：
</p>
</div>
<div class="outline-3" id="outline-container-orgd690085">
<h3 id="orgd690085">when… thenReturn…</h3>
<div class="outline-text-3" id="text-orgd690085">
<pre class="example">
when(spy.service()).thenReturn("spy!");
</pre>
<p>
使用 when 去设置模拟值时，他里面的代码逻辑依然会被执行，只是mock了返回结果
</p>
</div>
</div>
<div class="outline-3" id="outline-container-orgffdf463">
<h3 id="orgffdf463">doReturn…when…</h3>
<div class="outline-text-3" id="text-orgffdf463">
<div class="org-src-container">
<pre class="src src-java">doReturn(<span style="font-style: italic;">"spy!"</span>).when(spy).service();
</pre>
</div>
<p>
模拟值的话，则不会出现这个问题
</p>
</div>
</div>
</div>
</div>
<div class="status" id="postamble">
<p class="date">Date: 2019-10-9</p>
<p class="author">Author: gdme1320</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
